#include "w6100_udps_comm_op.h"
#include "device_resource.h"
#include "print_rtt.h"
#include "w6100_socket.h"

int W6100_udps_setup(uint8_t sn, uint16_t *port, uint8_t loopback_mode)
{
  uint8_t status;
  char *mode_msg;
  if (loopback_mode == AS_IPV4)
  {
    mode_msg = msg_v4;
  }
  else if (loopback_mode == AS_IPV6)
  {
    mode_msg = msg_v6;
  }
  else
  {
    mode_msg = msg_dual;
  }
  if (xSemaphoreTake(w6100_op_xStaticMutex, portMAX_DELAY) != pdTRUE)
  {
    return 0;
  }
  getsockopt(sn, SO_STATUS, &status);
  if (status != SOCK_CLOSED)
  {
#ifdef _LOOPBACK_DEBUG_
    LOG_ERROR("%d:Status not CLOSED(%d), closing socket\r\n", sn, status);
#endif
    close(sn);
    while (1)
    {
      getsockopt(sn, SO_STATUS, &status);
      if (status == SOCK_CLOSED)
      {
#ifdef _LOOPBACK_DEBUG_
        LOG_INFO("%d:Socket closed, status=%d\r\n", sn, status);
#endif
        break;
      }
      if (getSn_IR(sn) & Sn_IR_TIMEOUT)
      {
        setSn_IRCLR(sn, Sn_IR_TIMEOUT);
#ifdef _LOOPBACK_DEBUG_
        LOG_ERROR("%d:Close socket timeout, status=%d\r\n", sn, status);
#endif
        xSemaphoreGive(w6100_op_xStaticMutex);
        return SOCKERR_TIMEOUT;
      }
    }
  }
  switch (loopback_mode)
  {
  case AS_IPV4:
    socket(sn, Sn_MR_UDP4, port, SOCK_IO_BLOCK);
    break;
  case AS_IPV6:
    socket(sn, Sn_MR_UDP6, port, SOCK_IO_NONBLOCK);
    break;
  case AS_IPDUAL:
    socket(sn, Sn_MR_UDPD, port, SOCK_IO_NONBLOCK);
    break;
  }
  LOG_INFO("%d:Opened, UDP loopback, port [%d] as %s\r\n", sn, *port, mode_msg);
  xSemaphoreGive(w6100_op_xStaticMutex);
  return 0;
}
int W6100_udps_send(uint8_t sn, uint8_t *buf, uint16_t len, uint8_t *destip, uint16_t destport, uint8_t addr_len)
{
  uint16_t sentsize = 0;             // 已发送数据长度
  int ret = -1;                      // 函数返回值（sendto结果/错误码）
  uint8_t sock_status = SOCK_CLOSED; // Socket当前状态
  TickType_t xStartTick = 0;         // 发送开始时间（用于超时判断）

  if (len == 0 || len > 2048)
  {
    LOG_ERROR("UDP send: invalid len=%d (max=%d)\r\n", len, 2048);
    return -2; // 自定义错误码：长度非法
  }
  if (destport == 0 || destport > 65535)
  {
    LOG_ERROR("UDP send: invalid destport=%d\r\n", destport);
    return -2; // 自定义错误码：端口非法
  }

  // 2. 获取W6100操作互斥锁（永久等待，确保硬件操作原子性）
  if (xSemaphoreTake(w6100_op_xStaticMutex, portMAX_DELAY) != pdTRUE)
  {
    LOG_ERROR("UDP send: take w6100 mutex failed\r\n");
    return -1; // 互斥锁获取失败
  }

  // 3. 检查Socket状态（必须为UDP状态才允许发送）
  getsockopt(sn, SO_STATUS, &sock_status);
  if (sock_status != SOCK_UDP)
  {
    LOG_ERROR("UDP send: sn=%d invalid status=%d (need SOCK_UDP)\r\n", sn, sock_status);
    xSemaphoreGive(w6100_op_xStaticMutex); // 释放锁
    return -3;                             // 自定义错误码：Socket状态异常
  }

  // 4. 记录发送开始时间（用于总超时判断）
  xStartTick = xTaskGetTickCount();

  // 5. 循环发送数据（直到全部发送完成或超时/失败）
  while (sentsize < len)
  {
    // 5.1 发送剩余数据（buf+sentsize：未发送数据的起始地址；len-sentsize：剩余长度）
    ret = sendto(sn, buf + sentsize, len - sentsize, destip, destport, addr_len);

    // 5.2 处理sendto返回结果
    if (ret > 0)
    {
      // 发送成功：更新已发送长度
      sentsize += ret;
      LOG_INFO("UDP send: sn=%d, sent=%d/%d\r\n", sn, sentsize, len);
    }
    else if (ret == 0)
    {
      // 特殊情况：W6100发送缓冲区忙（SOCKERR_BUSY=0），短暂延时后重试
      LOG_INFO("UDP send: sn=%d busy, retry...\r\n", sn);
      vTaskDelay(pdMS_TO_TICKS(1)); // 1ms延时，降低CPU占用
    }
    else
    {
      // 发送失败：硬件错误（如Socket关闭、超时等）
      LOG_ERROR("UDP send: sn=%d sendto failed, err=%d\r\n", sn, ret);
      xSemaphoreGive(w6100_op_xStaticMutex); // 释放锁
      return ret;                            // 返回W6100硬件错误码（如SOCKERR_TIMEOUT、SOCKERR_CLOSED等）
    }

    // 5.3 检查总发送超时（避免无限循环）
    if ((xTaskGetTickCount() - xStartTick) > pdMS_TO_TICKS(500))
    {
      LOG_ERROR("UDP send: sn=%d timeout (sent=%d/%d)\r\n", sn, sentsize, len);
      xSemaphoreGive(w6100_op_xStaticMutex); // 释放锁
      return SOCKERR_TIMEOUT;                // 返回超时错误码
    }
  }

  // 6. 所有数据发送完成：释放锁并返回总长度
  xSemaphoreGive(w6100_op_xStaticMutex);
  LOG_INFO("UDP send: sn=%d success, total len=%d\r\n", sn, len);
  return len;
}
int W6100_udps_recv(uint8_t sn, uint8_t *buf, uint8_t *destip, uint16_t *destport, uint8_t *addr_len)
{
  uint16_t received_size;
  uint8_t status; // Socket状态（SOCK_UDP/SOCK_CLOSED等）
  int16_t ret;    // 函数返回值（接收长度/错误码）
  // 1. 获取W6100操作互斥锁（永久等待，直到获取成功）
  // 互斥锁用于保护W6100寄存器操作，避免多线程并发冲突
  if (xSemaphoreTake(w6100_op_xStaticMutex, portMAX_DELAY) != pdTRUE)
  {
    LOG_ERROR("Failed to take w6100 mutex\r\n");
    return 0;
  }

  // 2. 获取当前Socket状态
  getsockopt(sn, SO_STATUS, &status);

  // 3. 若Socket为UDP状态（正常工作状态）
  if (status == SOCK_UDP)
  {
    // 3.1 获取接收缓冲区中待读取的数据长度
    getsockopt(sn, SO_RECVBUF, &received_size);

    // 3.2 限制接收长度不超过缓冲区大小（避免缓冲区溢出）
    if (received_size > DATA_BUF_SIZE)
    {
      received_size = DATA_BUF_SIZE;
    }

    // 3.3 若有数据待接收
    if (received_size > 0)
    {
      // 关键检查：确保缓冲区非空（避免空指针访问）
      if (buf == NULL)
      {
        xSemaphoreGive(w6100_op_xStaticMutex);
        LOG_ERROR("Receive buffer is NULL\r\n");
        return -2; // 自定义错误码：缓冲区为空
      }

      // 3.4 接收UDP数据（从sn端口接收，存入buf，长度为received_size）
      // 注意：addr_len需提前初始化（如addr_len = sizeof(struct sockaddr_in)）
      ret = recvfrom(sn, buf, received_size, destip, destport, addr_len);

      // 3.5 释放互斥锁（必须在return前释放，避免死锁）
      xSemaphoreGive(w6100_op_xStaticMutex);

      // 3.6 返回接收结果（ret可能为负：接收失败，需根据W6100手册判断错误类型）
      if (ret < 0)
      {
        LOG_ERROR("UDP recv failed, sn=%d, err=%d\r\n", sn, ret);
      }
      return ret;
    }
    // 3.7 无数据待接收：释放锁并返回0
    else
    {
      xSemaphoreGive(w6100_op_xStaticMutex);
      return 0;
    }
  }
  // 4. 若Socket状态非UDP（异常状态）
  else
  {
    // 4.1 关闭异常Socket（强制释放Socket资源）
    close(sn);

    // 4.2 循环等待Socket关闭完成或超时
    while (1)
    {
      // 再次获取Socket状态，确认是否已关闭
      getsockopt(sn, SO_STATUS, &status);

      // 4.3 若Socket已关闭：释放锁并返回-1
      if (status == SOCK_CLOSED)
      {
#ifdef _LOOPBACK_DEBUG_
        LOG_INFO("%d: Socket closed normally, status=%d\r\n", sn, status);
#endif
        xSemaphoreGive(w6100_op_xStaticMutex);
        return -1;
      }

      // 4.4 检查Socket超时中断（Sn_IR_TIMEOUT：接收/发送超时）
      if (getSn_IR(sn) & Sn_IR_TIMEOUT)
      {
        // 清除超时中断标志（必须清除，否则会一直触发）
        setSn_IRCLR(sn, Sn_IR_TIMEOUT);
#ifdef _LOOPBACK_DEBUG_
        LOG_ERROR("%d: Close socket timeout, status=%d\r\n", sn, status);
#endif
        xSemaphoreGive(w6100_op_xStaticMutex);
        return SOCKERR_TIMEOUT; // W6100定义的超时错误码
      }

      // 可选：添加延时，降低CPU占用（避免死循环空转）
      vTaskDelay(pdMS_TO_TICKS(10));
    }
  }
}
int W6100_udps_recv_1(uint8_t sn, uint8_t *buf, uint8_t *destip, uint16_t *destport, uint8_t *addr_len)
{
  uint8_t status;        // Socket状态（SOCK_UDP/SOCK_CLOSED等）
  int16_t ret;           // 函数返回值（接收长度/错误码）
  int16_t received_size; // 接收缓冲区中待读取的数据长度
  if (xSemaphoreTake(w6100_op_xStaticMutex, portMAX_DELAY) != pdTRUE)
  {
    return 0;
  }
  getsockopt(sn, SO_STATUS, &status);
  if (status == SOCK_UDP)
  {
    getsockopt(sn, SO_RECVBUF, &received_size);
    if (received_size > DATA_BUF_SIZE)
    {
      received_size = DATA_BUF_SIZE;
    }
    if (received_size > 0)
    {
      ret = recvfrom(sn, buf, received_size, destip, destport, addr_len);
      xSemaphoreGive(w6100_op_xStaticMutex);
      return ret;
    }
    else
    {
      xSemaphoreGive(w6100_op_xStaticMutex);
      return 0;
    }
  }
  else
  {
    close(sn);
    while (1)
    {
      getsockopt(sn, SO_STATUS, &status);
      if (status == SOCK_CLOSED)
      {
#ifdef _LOOPBACK_DEBUG_
        LOG_INFO("%d:Socket closed, status=%d\r\n", sn, status);
#endif
        xSemaphoreGive(w6100_op_xStaticMutex);
        return -1;
      }
      if (getSn_IR(sn) & Sn_IR_TIMEOUT)
      {
        setSn_IRCLR(sn, Sn_IR_TIMEOUT);
#ifdef _LOOPBACK_DEBUG_
        LOG_ERROR("%d:Close socket timeout, status=%d\r\n", sn, status);
#endif
        xSemaphoreGive(w6100_op_xStaticMutex);
        return SOCKERR_TIMEOUT;
      }
    }
  }
}
